package socketmvc.core.processor.bean;

import socketmvc.core.context.IContext;
import socketmvc.core.packets.basic.IFilePacket;
import socketmvc.core.packets.basic.IMultiFilePacket;
import socketmvc.core.packets.basic.IPacket;
import socketmvc.core.packets.biz.SockFile;
import socketmvc.core.packets.biz.SockMultiFile;
import socketmvc.core.util.ClassUtils;

import java.lang.reflect.Type;

/**
 * Created by xueyanjun on 2018/1/17.
 *
 */
public class ProcessorMethodParam {

    private String name;
    private Class<?> clazz;
    private Type type;
    private ValOptimizer<?> optimizer;

    public ProcessorMethodParam() {}

    public ProcessorMethodParam(String name, Class<?> clazz, Type type) {
        this.name = name;
        this.clazz = clazz;
        this.type = type;
        this.optimizer = getValOptimizer(this);
    }

    public static ValOptimizer<?> getValOptimizer(ProcessorMethodParam methodParam){

        String paramName = methodParam.getName();
        Type paramType = methodParam.getType();
        Class<?> paramClass = methodParam.getClazz();

        if (ClassUtils.classAssignableFrom(paramClass, IPacket.class)) {
            return new ValOptimizer<IPacket>() {
                @Override
                public IPacket value(IContext context, IPacket packet) {
                    return packet;
                }
            };

        }
        if (ClassUtils.classAssignableFrom(paramClass,IContext.class)) {
            return new ValOptimizer<IContext>() {
                @Override
                public IContext value(IContext context, IPacket packet) {
                    return context;
                }
            };
        }

        // 封装一个ImFile类，用来接受二进制类型
        if (paramClass.equals(SockFile.class)) {
            return new ValOptimizer<SockFile>() {
                @Override
                public SockFile value(IContext context, IPacket packet) {
                    if (packet instanceof IFilePacket){
                        return ((IFilePacket) packet).toFile();
                    }
                    return null;
                }
            };
        }

        if (paramClass.equals(SockMultiFile.class)) {
            return new ValOptimizer<SockMultiFile>() {
                @Override
                public SockMultiFile value(IContext context, IPacket packet) {
                    if (packet instanceof IMultiFilePacket){
                        return ((IMultiFilePacket) packet).toMultiFile();
                    }
                    return null;
                }
            };
        }

        if (paramName == null || paramName.isEmpty() || paramName.equals("Param@Root")) {
            return new ValOptimizer<>() {
                @Override
                public Object value(IContext context, IPacket packet) {
                    return packet.toBean(paramType);
                }
            };
        }

        ValOptimizer<?> optimizer;
        // 基本数据类型
        if (paramClass.isPrimitive() || paramClass.equals(String.class) || ClassUtils.classAssignableFrom(paramClass, Number.class)) {
            String shortName = paramClass.getSimpleName();
            switch (shortName) {
                case "String" -> optimizer = new ValOptimizer<String>() {
                    @Override
                    public String value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getString(paramName);
                    }
                };
                case "int" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getIntValue(paramName);
                    }
                };
                case "Integer" -> optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getInteger(paramName);
                    }
                };
                case "long" -> optimizer  = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getLongValue(paramName);
                    }
                };
                case "Long" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getLong(paramName);
                    }
                };
                case "BigDecimal" -> optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getBigDecimal(paramName);
                    }
                };
                case "double" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getDoubleValue(paramName);
                    }
                };
                case "Double" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getDouble(paramName);
                    }
                };
                case "float" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getFloatValue(paramName);
                    }
                };
                case "Float" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getFloat(paramName);
                    }
                };
                case "short" -> optimizer  = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getShortValue(paramName);
                    }
                };
                case "Short" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getShort(paramName);
                    }
                };
                case "boolean" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getBooleanValue(paramName);
                    }
                };
                case "Boolean" ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getBoolean(paramName);
                    }
                };
                default ->  optimizer = new ValOptimizer<>() {
                    @Override
                    public Object value(IContext context, IPacket packet) {
                        return packet.getTextBodyAsObj().getObject(paramName,paramClass);
                    }
                };
            }
        } else {
            // 非基本数据类型
            optimizer = new ValOptimizer<>() {
                @Override
                public Object value(IContext context, IPacket packet) {
                    return packet.getTextBodyAsObj().getObject(paramName,paramType);
                }
            };
        }

        return optimizer;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Class<?> getClazz() {
        return clazz;
    }

    public void setClazz(Class<?> clazz) {
        this.clazz = clazz;
    }

    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    public ValOptimizer<?> getOptimizer() {
        return optimizer;
    }

    public void setOptimizer(ValOptimizer<?> optimizer) {
        this.optimizer = optimizer;
    }

    public static abstract class ValOptimizer<T>{
        public abstract T value(IContext context, IPacket packet);
    }
}
